using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace LiJ.Pay.Ali.Pay.SysTools
{
	/// <summary>
	///   rsa加密
	/// </summary>
	public class ZPayRsaAssist
	{
		private readonly RSA m_PublicRsa;

		private readonly RSA m_PrivateRsa;

		private readonly string m_Charset;

		internal string AppId
		{
			get;
			set;
		}

		/// <summary>
		///  构造函数
		/// </summary>
		/// <param name="privateKeyPem"></param>
		/// <param name="publicKeyPem"></param>
		/// <param name="charset"></param>
		public ZPayRsaAssist(string privateKeyPem, string publicKeyPem, string charset)
		{
			this.m_PublicRsa = ZPayRsaAssist.CreateRsaProviderFromPublicKey(publicKeyPem);
			this.m_PrivateRsa = ZPayRsaAssist.CreateRsaProviderFromPrivateKey(privateKeyPem);
			this.m_Charset = charset;
		}

		/// <summary>
		///  验签操作
		/// </summary>
		/// <param name="signContent"></param>
		/// <param name="sign"></param>
		/// <returns></returns>
		public bool CheckSign(string signContent, string sign)
		{
			byte[] bytes = Encoding.GetEncoding(this.m_Charset).GetBytes(signContent);
			return this.m_PublicRsa.VerifyData(bytes, Convert.FromBase64String(sign), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
		}

		/// <summary>
		/// 生成签名
		/// </summary>
		/// <param name="data"></param>
		/// <returns></returns>
		public string GenerateSign(string data)
		{
			if (this.m_PrivateRsa == null)
			{
				throw new Exception("您使用的私钥格式错误，请检查RSA私钥配置,charset = " + this.m_Charset);
			}
			byte[] bytes = Encoding.GetEncoding(this.m_Charset).GetBytes(data);
			return Convert.ToBase64String(this.m_PrivateRsa.SignData(bytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1));
		}

		private static RSA CreateRsaProviderFromPublicKey(string publicKeyString)
		{
			byte[] b = new byte[15]
			{
				48,
				13,
				6,
				9,
				42,
				134,
				72,
				134,
				247,
				13,
				1,
				1,
				1,
				5,
				0
			};
			using (MemoryStream input = new MemoryStream(Convert.FromBase64String(publicKeyString)))
			{
				using (BinaryReader binaryReader = new BinaryReader(input))
				{
					ushort num = 0;
					switch (binaryReader.ReadUInt16())
					{
					case 33072:
						binaryReader.ReadByte();
						break;
					case 33328:
						binaryReader.ReadInt16();
						break;
					default:
						return null;
					}
					if (!ZPayRsaAssist.CompareBytearrays(binaryReader.ReadBytes(15), b))
					{
						return null;
					}
					switch (binaryReader.ReadUInt16())
					{
					case 33027:
						binaryReader.ReadByte();
						break;
					case 33283:
						binaryReader.ReadInt16();
						break;
					default:
						return null;
					}
					if (binaryReader.ReadByte() != 0)
					{
						return null;
					}
					switch (binaryReader.ReadUInt16())
					{
					case 33072:
						binaryReader.ReadByte();
						break;
					case 33328:
						binaryReader.ReadInt16();
						break;
					default:
						return null;
					}
					num = binaryReader.ReadUInt16();
					byte b2 = 0;
					byte b3;
					switch (num)
					{
					case 33026:
						b3 = binaryReader.ReadByte();
						break;
					case 33282:
						b2 = binaryReader.ReadByte();
						b3 = binaryReader.ReadByte();
						break;
					default:
						return null;
					}
					int num2 = BitConverter.ToInt32(new byte[4]
					{
						b3,
						b2,
						0,
						0
					}, 0);
					if (binaryReader.PeekChar() == 0)
					{
						binaryReader.ReadByte();
						num2--;
					}
					byte[] modulus = binaryReader.ReadBytes(num2);
					if (binaryReader.ReadByte() != 2)
					{
						return null;
					}
					int count = binaryReader.ReadByte();
					byte[] exponent = binaryReader.ReadBytes(count);
					RSAParameters rSAParameters = default(RSAParameters);
					rSAParameters.Modulus = modulus;
					rSAParameters.Exponent = exponent;
					RSAParameters parameters = rSAParameters;
					RSA rSA = RSA.Create();
					rSA.ImportParameters(parameters);
					return rSA;
				}
			}
		}

		private static bool CompareBytearrays(byte[] a, byte[] b)
		{
			if (a.Length != b.Length)
			{
				return false;
			}
			int num = 0;
			for (int i = 0; i < a.Length; i++)
			{
				if (a[i] != b[num])
				{
					return false;
				}
				num++;
			}
			return true;
		}

		private static RSA CreateRsaProviderFromPrivateKey(string strKey)
		{
			return ZPayRsaAssist.DecodeRSAPrivateKey(Convert.FromBase64String(strKey));
		}

		private static RSA DecodeRSAPrivateKey(byte[] privkey)
		{
			MemoryStream memoryStream = new MemoryStream(privkey);
			BinaryReader binaryReader = new BinaryReader(memoryStream);
			try
			{
				switch (binaryReader.ReadUInt16())
				{
				case 33072:
					binaryReader.ReadByte();
					break;
				case 33328:
					binaryReader.ReadInt16();
					break;
				default:
					return null;
				}
				ushort num = binaryReader.ReadUInt16();
				if (num != 258)
				{
					return null;
				}
				if (binaryReader.ReadByte() != 0)
				{
					return null;
				}
				RSAParameters parameters = default(RSAParameters);
				int integerSize = ZPayRsaAssist.GetIntegerSize(binaryReader);
				parameters.Modulus = binaryReader.ReadBytes(integerSize);
				integerSize = ZPayRsaAssist.GetIntegerSize(binaryReader);
				parameters.Exponent = binaryReader.ReadBytes(integerSize);
				integerSize = ZPayRsaAssist.GetIntegerSize(binaryReader);
				parameters.D = binaryReader.ReadBytes(integerSize);
				integerSize = ZPayRsaAssist.GetIntegerSize(binaryReader);
				parameters.P = binaryReader.ReadBytes(integerSize);
				integerSize = ZPayRsaAssist.GetIntegerSize(binaryReader);
				parameters.Q = binaryReader.ReadBytes(integerSize);
				integerSize = ZPayRsaAssist.GetIntegerSize(binaryReader);
				parameters.DP = binaryReader.ReadBytes(integerSize);
				integerSize = ZPayRsaAssist.GetIntegerSize(binaryReader);
				parameters.DQ = binaryReader.ReadBytes(integerSize);
				integerSize = ZPayRsaAssist.GetIntegerSize(binaryReader);
				parameters.InverseQ = binaryReader.ReadBytes(integerSize);
				RSA rSA = RSA.Create();
				rSA.ImportParameters(parameters);
				return rSA;
			}
			finally
			{
				binaryReader.Dispose();
				memoryStream.Dispose();
			}
		}

		private static int GetIntegerSize(BinaryReader binr)
		{
			byte b = binr.ReadByte();
			if (b != 2)
			{
				return 0;
			}
			b = binr.ReadByte();
			int num = 0;
			switch (b)
			{
			case 129:
				num = binr.ReadByte();
				break;
			case 130:
			{
				byte b2 = binr.ReadByte();
				byte b3 = binr.ReadByte();
				num = BitConverter.ToInt32(new byte[4]
				{
					b3,
					b2,
					0,
					0
				}, 0);
				break;
			}
			default:
				num = b;
				break;
			}
			while (binr.ReadByte() == 0)
			{
				num--;
			}
			binr.BaseStream.Seek(-1L, SeekOrigin.Current);
			return num;
		}
	}
}
